﻿using System;
using System.Collections.Generic;
using UnityEngine;

namespace YooAssetsSystem.Fsm
{
    public class StateMachine : StateMachine<StateData>
    {
        public StateMachine(object owner) : base(owner)
        {
        }

        public StateMachine(object owner, StateData t) : base(owner, t)
        {
        }
    }

    public class StateMachine<T> where T : StateData
    {
        private readonly Dictionary<string, BaseStateNone> nodes = new Dictionary<string, BaseStateNone>(100);
        private BaseStateNone curNode;
        private BaseStateNone preNode;

        /// <summary>
        /// 状态机持有者
        /// </summary>
        public object Owner { private set; get; }

        public T ShareData { private set; get; }

        /// <summary>
        /// 当前运行的节点名称
        /// </summary>
        public string CurrentNode
        {
            get { return curNode != null ? curNode.GetType().FullName : string.Empty; }
        }

        /// <summary>
        /// 之前运行的节点名称
        /// </summary>
        public string PreviousNode
        {
            get { return preNode != null ? preNode.GetType().FullName : string.Empty; }
        }

        public event Action MachineStartEvent;
        public event Action MachineStopEvent;
        public event Action<StateNode<T>> ChangeStateEvent;

        public StateMachine(object owner)
        {
            Owner = owner;
            ShareData = default;
        }

        public StateMachine(object owner, T t)
        {
            Owner = owner;
            ShareData = t;
        }

        public bool IsRunning() => curNode != null;

        public bool NodeIsRunning<TNode>() where TNode : BaseStateNone
        {
            return NodeIsRunning(typeof(TNode));
        }

        public bool NodeIsRunning(Type type)
        {
            return CurrentNode == type.FullName;
        }

        /// <summary>
        /// 更新状态机
        /// </summary>
        public void Update()
        {
            if (curNode is StateNode<T> t)
            {
                t.OnUpdate();
            }
            else
            {
                // Debug.LogError($"找不到对应的状态节点 : {curNode}");
            }
        }

        public void Stop()
        {
            if (curNode is StateNode<T> t)
            {
                t.OnExit();
                preNode = null;
                curNode = null;
                ShareData.Clear();
                MachineStopEvent?.Invoke();
            }
            else
            {
                Debug.LogError($"找不到当前状态节点");
            }
        }

        public void Run<TNode>(T t) where TNode : BaseStateNone
        {
            ShareData = t;
            Run<TNode>();
        }

        public void Run(Type type, T t)
        {
            ShareData = t;
            Run(type);
        }

        /// <summary>
        /// 启动状态机
        /// </summary>
        public void Run<TNode>() where TNode : BaseStateNone
        {
            Run(typeof(TNode));
        }

        public void Run(Type entryNode)
        {
            Run(entryNode?.FullName);
        }

        public void Run(string entryNode)
        {
            if (curNode != null)
            {
                Debug.LogError($"状态机已启动: {CurrentNode}");
                return;
            }

            curNode = TryGetNode(entryNode);
            preNode = curNode;

            if (curNode is StateNode<T> t)
            {
                t.OnEnter();
                MachineStartEvent?.Invoke();
            }
            else
            {
                Debug.LogError($"找不到对应的状态节点 : {entryNode}");
            }
        }

        /// <summary>
        /// 加入一个节点
        /// </summary>
        public void AddNode<TNode>() where TNode : BaseStateNone
        {
            var nodeType = typeof(TNode);
            var stateNode = Activator.CreateInstance(nodeType) as BaseStateNone;
            AddNode(stateNode);
        }

        public void AddNode(BaseStateNone stateNode)
        {
            if (stateNode == null)
                throw new ArgumentNullException();

            var nodeType = stateNode.GetType();
            var nodeName = nodeType.FullName;

            if (nodes.ContainsKey(nodeName) == false && stateNode is StateNode<T> t)
            {
                t?.OnCreate(this);
                nodes.Add(nodeName, stateNode);
            }
            else
            {
                Debug.LogError($"该状态节点已存在 : {nodeName}");
            }
        }

        /// <summary>
        /// 转换状态节点
        /// </summary>
        public void ChangeState<TNode>() where TNode : BaseStateNone
        {
            var nodeType = typeof(TNode);
            var nodeName = nodeType.FullName;
            ChangeState(nodeName);
        }

        public void ChangeState(Type nodeType)
        {
            var nodeName = nodeType.FullName;
            ChangeState(nodeName);
        }

        public void ChangeState(string nodeName)
        {
            if (string.IsNullOrEmpty(nodeName))
            {
                Debug.LogError("State node name is null or empty");
                return;
            }

            if (TryGetNode(nodeName) is { } node)
            {
                preNode = curNode;
                if (curNode is StateNode<T> t) t.OnExit();
                curNode = node;
                if (curNode is StateNode<T> t1)
                {
                    t1.OnEnter();
                    ChangeStateEvent?.Invoke(t1);
                }
            }
            else
            {
                Debug.LogError($"找不到对应的状态节点 : {nodeName}");
            }
        }

        private BaseStateNone TryGetNode(string nodeName)
        {
            nodes.TryGetValue(nodeName, out var result);
            return result;
        }
    }
}